package com.pai4j.client.filter;

import com.pai4j.common.config.properties.OauthProperties;
import com.pai4j.common.constants.WebConstant;
import com.pai4j.common.enums.BaseErrCodeEnum;
import com.pai4j.common.enums.RedisKeyEnum;
import com.pai4j.common.exception.SafeEventException;
import com.pai4j.common.helper.SessionHelper;
import com.pai4j.common.util.JsonUtil;
import com.pai4j.common.util.RedisUtil;
import com.pai4j.common.util.RemoteIpUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  拦截OAuth认证
 *
 * @author: CYM-pai
 * @date: 2025/05/05 14:46
 **/
@Slf4j
@Order(-6)
@WebFilter(filterName = "oauthFilter", urlPatterns = {"/*"})
@Component
public class OauthFilter implements Filter {
    // OAuth 属性配置
    @Resource
    private OauthProperties oauthProperties;
    @Autowired
    private RedisUtil redisUtil;
    
    
    /***
     * IP_CONTROL_WHITE_LIST:该段代码定义了一个静态常量 IP_CONTROL_WHITE_LIST，
     * 用于存储不需要IP控制的API路径。
     * 静态代码块中初始化了两个白名单接口路径：文件上传和获取当前用户信息接口。
     */
    private static List<String> IP_CONTROL_WHITE_LIST = new ArrayList<>();

    /***
     * OAUTH_WHITE_LIST:该段代码定义了一个静态常量 OAUTH_WHITE_LIST，
     * 用于存储不需要OAuth认证的API路径。
     * 这些接口可以直接访问，无需登录验证。
     */
    private static List<String> OAUTH_WHITE_LIST = new ArrayList<>();

    static {
        IP_CONTROL_WHITE_LIST.add("/oss-service/oss/upload/");
        IP_CONTROL_WHITE_LIST.add("/user-service/user/info/{userId}");
       /**
        // OAuth认证白名单 - 这些接口不需要登录验证
        OAUTH_WHITE_LIST.add("/JianLipai-service/user/ai/chat/completion/stream");
        */
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 过滤器初始化方法
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 请求资源URI
        String uri = request.getRequestURI();
        
        /**
        // 检查OAuth白名单，如果在白名单中则直接放行
        if (OAUTH_WHITE_LIST.contains(uri)) {
            System.out.println("OAuth白名单接口，直接放行: " + uri);
            filterChain.doFilter(request, response);
            return;
        }
        */
        
        // 判断是否已经登录，如果已经登录则直接进入后续方法。
        String satoken = request.getHeader("token");
        System.out.println("satoken:" + satoken);

        String userId = redisUtil.get(RedisKeyEnum.OPENID_LOGINID_CACHE.getKey(satoken));
        // 获取客户端IP
        String ip = RemoteIpUtil.getRemoteIpByRequest(request);
        System.out.println("ip:" + ip);
        //  获取用户的UA信息
        String userAgent = request.getHeader("User-Agent");

        // 校验IP黑名单
        if (!IP_CONTROL_WHITE_LIST.contains(uri)) {
            ipBlackListCheck(uri, ip, JsonUtil.toJsonString(request.getParameterMap()));
        }
        if (StringUtils.isNotBlank(userId)) {
            // 请求头中的userId不为空，说明已经登录
            SessionHelper.setClientUserInfo(userId, ip, userAgent);
            System.out.println("userId:" + userId + ", ip:" + ip + ", userAgent:" + userAgent);
            try {
                filterChain.doFilter(request, response);
            } finally {
                SessionHelper.clear();
            }
            return;
        }
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("satoken".equals(cookie.getName())) {
                    //System.out.println("Cookie name: " + cookie.getName() + ", value: " + cookie.getValue());
                    String token = cookie.getValue();
                    userId =  redisUtil.get(RedisKeyEnum.OPENID_LOGINID_CACHE.getKey(token));
                    System.out.println("userId:" + userId + ", token:" + token);
                    SessionHelper.setUserId(userId);
                    try {
                        filterChain.doFilter(request, response);
                    } finally {
                        SessionHelper.clear();
                    }
                    return;
                }
            }
        }
    }

    /**
     * 处理未登录情况下的响应
     * @param request HTTP请求
     * @param response HTTP响应
     */
    private void unLogin(HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> responseMap = new HashMap<>();
        // 设置字符编码为 UTF-8
        response.setCharacterEncoding("UTF-8");
        // 设置内容类型和字符编码
        response.setContentType("application/json;charset=UTF-8");
        responseMap.put("code", BaseErrCodeEnum.UN_LOGIN.getCode());
        responseMap.put("message", BaseErrCodeEnum.UN_LOGIN.getMessage());
        responseMap.put("redirect_url", getRedirectUrl(request));
        try {
            response.getWriter().println(JsonUtil.toJsonString(responseMap));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取重定向URL
     * @param request HTTP请求
     * @return 重定向URL
     */
    private String getRedirectUrl(HttpServletRequest request) {
        String serverUrl = oauthProperties.getServerUrl();
        String originUrl = request.getHeader("origin-url");
        return String.format(serverUrl, URLEncoder.encode(originUrl));
    }
    
    /**
     * 校验IP请求黑名单
     *
     * @param url
     * @param ip
     * @param param
     */
    private void ipBlackListCheck(String url, String ip, String param) {
        String blackCacheKey = RedisKeyEnum.IP_BLACK_CACHE.getKey();
        if (redisUtil.sIsMember(blackCacheKey, ip)) {
            throw new SafeEventException("非法访问！！恶意攻击ip将提交公安机关，对服务造成的所有损失需承担所有法律责任与赔偿！");
        }
        if (StringUtils.isBlank(url) || !url.startsWith("/api")) {
            return;
        }
        
        String ipBlackListCacheKey = RedisKeyEnum.IP_BLACK_LIST_CACHE.getKey(ip);
        if (redisUtil.exists(ipBlackListCacheKey)) {
            long expireTime = redisUtil.getKeysExpireTime(ipBlackListCacheKey);
            String time = (expireTime / 60 == 10 ? 10 : expireTime / 60 + 1) + "分钟";
            throw new SafeEventException("IP访问太频繁被关小黑屋啦，请"+time+"后重试");
        }
        String lock = RedisKeyEnum.IP_BLACK_LIST_REQUEST_LOCK.getKey(url, ip, param);
        long count = redisUtil.increx(lock, 1);
        if (count > 20) {
            redisUtil.remove(lock);
            redisUtil.set(ipBlackListCacheKey, WebConstant.CACHE_NONE, RedisKeyEnum.IP_BLACK_LIST_CACHE.getExpireTime());
            throw new SafeEventException("IP访问太频繁，加入黑名单，请10分钟后重试");
        }
    }
    
    
    @Override
    public void destroy() {
        // 过滤器销毁方法
    }
}
